use chrono::Local;
use crate::builder::entity_builder::EntityBuilder;
use crate::{ApplicationConfig, table_name_to_entity_name, TableName};
use crate::builder::mapper_builder::MapperBuilder;
use crate::builder::xml_builder::XmlBuilder;

mod entity_builder;
mod xml_builder;
mod mapper_builder;

trait Builder {
    fn build(&self) -> String;
    fn build_file(&self);
}

pub struct Dispatch {
    member: Vec<Box<dyn Builder>>,
}

impl Dispatch {

    pub fn new(table: TableName, config: ApplicationConfig) -> Self {
        let base_path = config.project_path.unwrap();
        let entity_path = config.entity.entity_path.unwrap();
        let entity_name = table_name_to_entity_name(table.table_name.clone(), config.database.table_prefix.clone());
        let namespace = format!("{}.{}", entity_path, entity_name);
        let mapper_namespace = format!("{}.mapper", config.package_path);
        let result_type = format!("{}.mapper.{}Mapper", config.package_path, entity_name);

        let time_format = Local::now().format("%Y-%m-%d %H:%M:%S").to_string();
        let notes = format!("\n/**\n * @author: {}\n * @description: {}\n * @date: {}\n * @version: 1.0\n */\n", config.author.unwrap(), table.table_comment.unwrap_or(" ".to_string()), time_format);

        let xml_builder = XmlBuilder::new(
            base_path.as_str(),
            entity_name.as_str(),
            result_type.as_str(),
            namespace.as_str(),
            table.table_fields.clone()
        );

        let mapper_builder = MapperBuilder::new(
            base_path.as_str(),
            notes.as_str(),
            entity_path.as_str(),
            mapper_namespace.as_str(),
            entity_name.as_str()
        );

        let entity_builder = EntityBuilder::new(
            base_path.as_str(),
            notes.as_str(),
            entity_path.as_str(),
            entity_name.as_str(),
            table.table_fields.clone()
        );

        Dispatch {
            member: vec![
                Box::new(xml_builder),
                Box::new(mapper_builder),
                Box::new(entity_builder),
            ]
        }

    }



    pub fn dispatch(&self) {
        self.member.iter().for_each(|item| item.build_file());
    }
}

#[cfg(test)]
mod tests {

    #[test]
    fn test_dispatch() {
        // let mut dispatch = Dispatch::new();
        // dispatch.dispatch()
    }

}


